#!/usr/bin/env python
# -*- coding: utf8 -*-

# mplayer-lastfm (mkaplayer) is part of http://code.google.com/p/camtools,
# Copyright 2009 Camille Huot,
# and is licensed under http://www.gnu.org/copyleft/gpl.html

# Mkaplayer is a wrapper script written in Python which plays your Matroska
# music files with the mplayer binary and sends information about the songs to
# last.fm. It's called scrobbling.

# WARNING: to use it, you need lastfmsubmitd and hachoir-parser
# * lastfmsubmitd
#   Please see http://www.red-bean.com/~decklin/software/lastfmsubmitd/
#   and instructions inside my lmplayer (from the mplayer-lastfm distribution).
# * hachoir-parser
#   A Python library available here: http://hachoir.org/wiki/hachoir-parser

# More information about Matroska, chapters and tags are available here:
# http://www.cameuh.net/pmwiki.php/Docs/MatroskaAudio

MPLAYERBIN = '/usr/bin/mplayer'
DEBUG=False

print "mkaplayer © Camille Huot 2009."

import sys
try:
 file = sys.argv[1]
except:
 print "descr: play a Matroska file with MPlayer & send tags (if any) to LastFM"
 print "usage: mkaplayer <matroska_audio_file>"
 sys.exit(0)
 
import thread

try:
 import hachoir_parser
except:
 print "Failed to load hachoir_parser"
 sys.exit(0)

chapters = []
album_artist = None
album_title = None
chapter_artist = {}
chapter_title = {}
lastfm=True
def MkaParse():
 print "Parsing Chapters"
 chap = []
 global album_artist
 global album_title
 global chapter_artist
 global chapter_title
 global lastfm
 
 print "Opening file"
 parser = hachoir_parser.createParser(unicode(file))
 if not parser.validate():
  print "[!] The file doesn't seem to be valid."
  lastfm=False
  return

 i=0
 while True:
  path = '/Segment[0]/Chapters/EditionEntry[0]/ChapterAtom[%d]' % i
  try:
   chap.append(( \
    parser[path+'/ChapterTimeStart/unsigned'].value / 1000000000,
    parser[path+'/ChapterUID/unsigned'].value))
  except Exception, e:
   if DEBUG: print "[1] %s" % (e)
   break
  i += 1
 
 if len(chap) == 0:
  print "[!] No chapters found. LastFM plugin disabled!"
  lastfm=False
 
 print 'Parsing Tags'
 # construction de la liste des tags
 i = 0
 tagpath = '/Segment[0]/Tags[0]/Tag[%d]'
 tagtypepath = tagpath + '/Targets/TargetType/string'
 taguidpath  = tagpath + '/Targets/ChapterUID[0]/unsigned'
 simpletagnamepath   = tagpath + '/SimpleTag[%d]/TagName/unicode'
 simpletagstringpath = tagpath + '/SimpleTag[%d]/TagString/unicode'
 while len(chap) != 0:
  try:
   # cas de l'album
   if u'ALBUM' == parser[tagtypepath % i].value:
    j=0
    while True:
     try:
      if u'ARTIST' == parser[simpletagnamepath % (i, j)].value:
       album_artist = parser[simpletagstringpath % (i, j)].value
      elif u'TITLE' == parser[simpletagnamepath % (i, j)].value:
       album_title  = parser[simpletagstringpath % (i, j)].value
     except Exception, e:
      if DEBUG: print "[2] %s" % (e)
      break
     j += 1
   # cas de la piste
   elif u'TRACK' == parser[tagtypepath % i].value:
    j=0
    while True:
     try:
      if u'ARTIST' == parser[simpletagnamepath % (i, j)].value:
       chapter_artist[parser[taguidpath % i].value] = \
        parser[simpletagstringpath % (i, j)]
      elif u'TITLE' == parser[simpletagnamepath % (i, j)].value:
       chapter_title[parser[taguidpath % i].value] = \
        parser[simpletagstringpath % (i, j)]
     except Exception, e:
      if DEBUG: print "[3] %s" % (e)
      break
     j += 1
  except Exception, e:
   if DEBUG: print "[4] %s" % (e)
   break
  i += 1
 if album_title == None or len(chapter_title) == 0:
  print "[!] No or incomplete global tags, LastFM disabled."
  lastfm=False
 else:
  global chapters
  chapters=chap

def get_chapteruid_by_time(time):
 uid=None
 for chapter in chapters:
  if time >= chapter[0]:
   uid=chapter[1]
  else:
   break
 return uid

def MkaPlay():
 print "Playing file"
 
 import subprocess
 p=subprocess.Popen((MPLAYERBIN, file),
  bufsize=-1, stdout=subprocess.PIPE, universal_newlines=True)
 
 i=0
 last=None
 while p.poll() == None:
  a=p.stdout.readline()
  if not a.startswith('A:'):
   print a,
   continue
  
  # sans chapitrage ou sans tag, on s'arrete là
  if lastfm is False or len(chapters) == 0:
   continue
  
  # on ne traite pas toutes les lignes
  if i > 0:
   i-=1
   continue
 
  # dans quel chapitre nous trouvons-nous ?
  uid=get_chapteruid_by_time(int(float(a[2:].split()[0])))
 
  # si nous avons changé, on affiche les infos + envoie à LastFM
  if uid != last:
   last = uid
 
   try:
    trackname = chapter_title[uid]
   except:
    print "[!] Track title not found."
    continue
 
   try:
    trackartist = chapter_artist[uid]
   except:
    trackartist = album_artist
   if trackartist == None:
    print "[!] Artist name not found."
    continue
 
   print "Listening: %s - %s - %s" % (trackartist, album_title, trackname)
   pp=subprocess.Popen(('lastfmsubmit',
    '--artist', unicode(trackartist),
    '--title', unicode(trackname),
    '--album', unicode(album_title),
    '--length', '60',
    '--quiet'))
  i=150

thread.start_new_thread(MkaParse, ())
MkaPlay()
